import Map from 'ol/Map';
import Select from 'ol/interaction/Select';
import DragBox from 'ol/interaction/DragBox';
import Collection from 'ol/Collection';
import Feature from 'ol/Feature';
import Point from 'ol/geom/Point';
import Polygon from 'ol/geom/Polygon';
import { platformModifierKeyOnly } from 'ol/events/condition';
import Style from 'ol/style/Style';
import Stroke from 'ol/style/Stroke';
import Fill from 'ol/style/Fill';
import Circle from 'ol/style/Circle';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import { toLonLat } from 'ol/proj';

// 定义回调函数的类型，它将在框选结束后被调用，并接收选中的特征集合
export type OnBoxSelectEndCallback = (selectedFeatures: Collection<Feature<Point>>) => void;

// 定义框选矩形的可视化样式
const defaultDragBoxStyle = new Style({
  stroke: new Stroke({
    color: 'rgba(0, 255, 255, 1)', // 青色边框
    width: 2,
  }),
  fill: new Fill({
    color: 'rgba(0, 255, 255, 0.2)', // 半透明青色填充
  }),
});

/**
 * 定义 BoxSelectHandler 构造函数的选项接口，方便扩展。
 */
export interface BoxSelectHandlerOptions {
  map: Map; // OpenLayers 地图实例
  vectorSource: VectorSource<Feature<Point>>; // 包含要进行框选操作的特征的矢量源
  onBoxSelectEnd: OnBoxSelectEndCallback; // 框选结束后调用的回调函数
  selectStyle?: Style; // 可选的，用于选中特征的样式
}

/**
 * BoxSelectHandler 类用于封装 OpenLayers 的框选功能。
 * 它结合了 Select 和 DragBox 交互，并允许自定义框选结果的处理逻辑。
 */
export class BoxSelectHandler {
  private map: Map; // OpenLayers 地图实例
  private vectorSource: VectorSource<Feature<Point>>; // 包含可选择特征的矢量源
  private selectedFeatures: Collection<Feature<Point>>; // Select 交互用来存储选中特征的集合
  private selectInteraction: Select; // Select 交互实例（用于点击选择）
  private dragBoxInteraction: DragBox; // DragBox 交互实例（用于绘制框选矩形）
  private dragBoxSource: VectorSource<Feature<Polygon>>; // 用于显示框选矩形的矢量源
  private dragBoxLayer: VectorLayer<VectorSource<Feature<Polygon>>>; // 用于显示框选矩形的矢量层
  private onBoxSelectEndCallback: OnBoxSelectEndCallback; // 框选结束后的回调函数

  /**
   * 构造函数
   * @param options 包含所有构造函数参数的对象
   */
  constructor(options: BoxSelectHandlerOptions) {
    // 从 options 对象中解构出参数
    const { map, vectorSource, onBoxSelectEnd, selectStyle } = options;

    this.map = map;
    this.vectorSource = vectorSource;
    this.onBoxSelectEndCallback = onBoxSelectEnd;

    // 初始化 Select 交互的选中特征集合。这个集合会同时被单点点击和框选操作更新。
    this.selectedFeatures = new Collection<Feature<Point>>();

    // 初始化 Select 交互（主要处理单点点击选择）
    this.selectInteraction = new Select({
      features: this.selectedFeatures, // 绑定到 Select 交互的共享选中特征集合
      style: selectStyle || new Style({ // 使用传入的样式或默认选中样式
        image: new Circle({
          radius: 8,
          fill: new Fill({ color: 'rgba(0, 255, 255, 0.8)' }),
          stroke: new Stroke({ color: 'rgba(0, 255, 255, 1)', width: 3 }),
        }),
      }),
    });

    // 初始化用于显示拖拽框的矢量源和矢量层
    this.dragBoxSource = new VectorSource<Feature<Polygon>>();
    this.dragBoxLayer = new VectorLayer({
      source: this.dragBoxSource,
      style: defaultDragBoxStyle,
    });

    // 初始化 DragBox 交互（主要处理拖拽绘制矩形框）
    this.dragBoxInteraction = new DragBox({
      condition: platformModifierKeyOnly, // 只有在按住平台修饰键（Ctrl/Cmd）时才激活 DragBox
    });

    this.addInteractions(); // 将交互添加到地图中
    this.addEventListeners(); // 添加交互的事件监听器
  }

  /**
   * 将 Select 和 DragBox 交互以及框选可视化层添加到地图中。
   */
  private addInteractions() {
    this.map.addInteraction(this.selectInteraction);
    this.map.addInteraction(this.dragBoxInteraction);
    this.map.addLayer(this.dragBoxLayer); // 确保框选可视化层在地图上可见
  }

  /**
   * 添加交互的事件监听器。
   */
  private addEventListeners() {
    // 监听 Select 交互的 'select' 事件（由单点点击触发）
    this.selectInteraction.on('select', (event) => {
      console.log('--- Select (单点点击) 事件触发 ---');
      // selectedFeatures 集合已经由 Select 交互本身更新
      // 如果需要区分单点点击和框选后的处理，可以在这里添加额外逻辑
      this.logSelectedFeatures(event.target.getFeatures()); // 记录当前选中的特征信息
    });

    // 监听 DragBox 交互的 'boxstart' 事件
    // 当用户开始拖拽框选时触发
    this.dragBoxInteraction.on('boxstart', () => {
      this.selectedFeatures.clear(); // 开始新的框选时，清除所有之前选中的特征
      this.dragBoxSource.clear(); // 清除任何之前留下的框选可视化矩形
      console.log('--- 框选操作开始 ---');
    });

    // 监听 DragBox 交互的 'boxdrag' 事件
    // 当用户拖拽框选过程中持续触发，用于实时绘制框选矩形
    this.dragBoxInteraction.on('boxdrag', () => {
      this.dragBoxSource.clear(); // 清除上一帧的框选矩形
      const geometry = this.dragBoxInteraction.getGeometry(); // 获取当前拖拽的矩形几何对象
      if (geometry) {
        this.dragBoxSource.addFeature(new Feature(geometry)); // 将当前矩形作为 Feature 添加到可视化源中
      }
    });

    // 监听 DragBox 交互的 'boxend' 事件
    // 当用户完成拖拽框选（释放鼠标）时触发
    this.dragBoxInteraction.on('boxend', () => {
      const extent = this.dragBoxInteraction.getGeometry()!.getExtent(); // 获取最终框选矩形的地理范围
      console.log('--- 框选操作完成 ---');
      console.log('框选范围:', extent);

      this.dragBoxSource.clear(); // 框选结束后，清除框选矩形的实时显示

      // 在填充新的选中特征之前，清除当前选中集合中的所有特征
      this.selectedFeatures.clear();

      // 遍历矢量源中的所有特征，找出与框选范围相交的特征，并将其添加到选中集合中
      this.vectorSource.forEachFeatureIntersectingExtent(extent, (feature) => {
        // 确保特征是 Feature 实例，并推送到类型兼容的集合中
        if (feature instanceof Feature) {
          this.selectedFeatures.push(feature as Feature<Point>);
        }
      });

      // 调用外部传入的回调函数，将选中的特征集合传递出去，以便进行业务处理
      this.onBoxSelectEndCallback(this.selectedFeatures);
    });
  }

  /**
   * 辅助方法：将选中的特征信息输出到控制台。
   * @param features 要输出的特征集合。
   */
  private logSelectedFeatures(features: Collection<Feature<Point>>) {
      if (features.getLength() > 0) {
        console.log('当前选中特征:');
        features.forEach(feature => {
          const geometry = feature.getGeometry() as Point; // 获取几何对象并断言为 Point
          const coordinates = toLonLat(geometry.getCoordinates()); // 转换为经纬度
          console.log(`  ID: ${feature.get('id') || 'N/A'}, 名称: ${feature.get('name') || 'N/A'}, 坐标: [${coordinates[0].toFixed(4)}, ${coordinates[1].toFixed(4)}]`);
        });
      } else {
        console.log('当前没有选中特征。');
      }
  }

  /**
   * 销毁 BoxSelectHandler 实例，移除所有交互和图层，防止内存泄漏。
   */
  destroy() {
    this.map.removeInteraction(this.selectInteraction);
    this.map.removeInteraction(this.dragBoxInteraction);
    this.map.removeLayer(this.dragBoxLayer); // 移除框选可视化层
    this.selectedFeatures.clear(); // 清空选中的特征
    this.dragBoxSource.clear(); // 清空框选源
    console.log('BoxSelectHandler 已销毁。');
  }

  /**
   * 获取当前选中的特征集合。
   * @returns 选中的特征集合。
   */
  public getSelectedFeatures(): Collection<Feature<Point>> {
    return this.selectedFeatures;
  }
} 